<?php

namespace App\Models;

use App\Library\Datatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

/**
 * App\Models\Goods
 *
 * @property int $goods_id
 * @property string $goods_name 商品名称
 * @property int $cat_id goods_cat表的外键 分类id
 * @property float|null $price 商品的原价
 * @property float|null $discount_price 商品的现价或者打折价
 * @property float $sales_num 商品销量
 * @property float $stock 库存量
 * @property string|null $image 商品主图
 * @property string|null $ship_address 商品发货地
 * @property int $marketable 上下架状态 0-下架 1-上架
 * @property string|null $detail_content 商品详情介绍 富文本编辑内容
 * @property int $disabled 删除状态 0-未删除 1-已删除
 * @property int $sort 商品排序的序号
 * @property string|null $bn 商品编码
 * @property \Carbon\Carbon|null $created_at
 * @property \Carbon\Carbon|null $updated_at
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Comment[] $comment
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereBn($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereCatId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereDetailContent($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereDisabled($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereDiscountPrice($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereGoodsId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereGoodsName($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereImage($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereMarketable($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods wherePrice($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereSalesNum($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereShipAddress($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereSort($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereStock($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereUpdatedAt($value)
 * @mixin \Eloquent
 * @property int $click_count 浏览量
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Goods whereClickCount($value)
 */
class Goods extends Model
{
    protected $table = 'goods';
    protected $primaryKey = 'goods_id';
    protected $guarded = [];

    public $error;

    private $tmp_price = 0;
    private $tmp_sku_store = 0;
    private $tmp_discount_money = 0;
    private $tmp_is_discount = 0;

    public function comment()
    {
      return $this->hasMany('App\Models\Comment','goods_id');
    }

    /**
     * spu列表的获取
     */
    public function data($request)
    {
        $goods_list = $this->goods_list_query($request);
        $goods_list = Datatable::packQuery($request->input(),$goods_list)->get()->toArray();
        $goods_list = Datatable::packResult($request->input(),$goods_list);
        foreach($goods_list['data'] as &$goods){
            $goods_model = GoodsImage::query()->where('goods_id','=',$goods['goods_id']);
            $default_model  = $goods_model->where('is_default','=',1)->first();
            $not_default_model = $goods_model -> first();
            $not_default_image = empty($not_default_model)?'':$not_default_model->image;
            $goods['image'] = empty($default_model) ? $not_default_image : $default_model->image;
            $goods['market_status'] = empty($goods['marketable']) ? '未上架' : '已上架';
        }
        return $goods_list;
    }

    /**
     * 公共的query join方法
     */
    public function goods_list_query($postdata)
    {
        return $this->newQuery()
            -> select(
                $this->table.'.*',
                 DB::raw('IFNULL(discount_price,price) discount_price')
//                 DB::raw('IF(discount_price=0,price,discount_price) discount_price')

            )
            -> where($this->table.'.disabled',0);
    }

    public function admin_api_goods_list($potdata)
    {
        $query = $this -> goods_list_query($potdata);
        $list  = $query -> paginate(10);
        $pages = $list -> links()->tohtml();
        return [
          'list'  => $list -> toArray(),
          'pages' => $pages
        ];

    }

    /**
     * spu的新增
     *
     * @param $params
     * @return bool
     * @throws Exception
     */
    public function add($params)
    {
        DB::beginTransaction();
        $time = time();
        try {
            //商品数据
            $goods_id = $this->insertGetId([
                'goods_name'     => $params['Goods']['name'],
                'detail_content' => $params['Goods']['intro'],
                'cat_id'         => empty($params['Goods']['cat_id'])?0:$params['Goods']['cat_id'],
                'sort'           => empty($params['Goods']['sort'])?0:$params['Goods']['sort'],
                'unit'           => $params['Goods']['unit'],
                'price'          => empty($params['Goods']['price'])? 0 : $params['Goods']['price'],
                'discount_price' => empty($params['Goods']['discount_price'])? null : $params['Goods']['discount_price'],
                'stock' => empty($params['Goods']['stock'])? 0 : $params['Goods']['stock'],

            ]);

            if (!$goods_id) {
               throw new \Exception('goods表添加失败');
            }

            //sku的添加
            $this -> add_goods_props($goods_id, $params);

            //商品图片的保存
            $this -> save_goods_iamge($goods_id,$params);
            DB::commit();
            return true;
        } catch (\Exception $e) {
            $this->error = $e->getMessage();
            DB::rollBack();
            return false;
        }
    }

    /**商品的编辑
     * @param $params
     * @return bool
     */
    public function edit($spu_id,$params)
    {
        DB::beginTransaction();
        $time = time();
        try {
            if(isset($params['Goods']['price'])){
                $price_arr['price'] =  $params['Goods']['price'];
            }
            if(isset($params['Goods']['discount_price'])){
                $price_arr['discount_price'] =  empty($params['Goods']['discount_price'])?null:$params['Goods']['discount_price'];
            }
            if(isset($params['Goods']['stock'])){
                $price_arr['stock'] =  $params['Goods']['stock'];
            }

            #商品基本信息
            $this->newQuery()->where('goods_id',$spu_id)->update(array_merge([
                'goods_name'     => $params['Goods']['name'],
                'detail_content' => $params['Goods']['intro'],
                'cat_id'         => empty($params['Goods']['cat_id'])?0:$params['Goods']['cat_id'],
                'sort'           => empty($params['Goods']['sort'])?0:$params['Goods']['sort'],
                'unit'         => $params['Goods']['unit'],
            ],$price_arr));

            //sku的编辑
            $res = $this->edit_goods_props($spu_id,$params);

            #商品图片的编辑
            $this -> save_goods_iamge($spu_id,$params);

            DB::commit();
            return true;
        } catch (\Exception $e) {
            $this->error = $e->getMessage();
            DB::rollBack();
            return false;
        }
    }

    /**
     * 删除商品
     *
     * @param $goods_id  int 商品的spu_id
     * @return bool      成功返回true 失败返回false
     * @throws \Exception
     */
    public function del($goods_id)
    {
        DB::beginTransaction();
        $time = time();
        try {
            //将spu表更新为disabled = 1
            $this->where('goods_id',$goods_id)->update(['disabled'=>'1']);

            //将sku表更新为disabled = 1
            Product::where('goods_id',$goods_id)->update(['disabled'=>'1']);

            //更新商品图片表
            GoodsImage::where('goods_id',$goods_id)->update(['disabled'=>1]);

            //更新商品规格表的规格为disabled = 1
            sku_props_vals::where('spu_id',$goods_id)->update(['disabled'=>'1']);

            //会员购物车
//            $command->createCommand()->delete(
//                CartGoods::tableName(),
//                'goods_id = :goods_id',
//                [':goods_id'=>$goods_id]
//            )->execute();
            DB::commit();
            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            return false;
        }
    }

    /**获取用于前端显示的分类列表，最多两级分类
     * @param $cate
     * @param string $html
     * @param int $pid
     * @param int $level
     * @return array
     */
    public function getHtmlCate($cate,$html="&nbsp;&nbsp;&nbsp;&nbsp;",$pid=0, $level=0){
        //定义空数组
        $arr = array();
        //遍历数组
        foreach($cate as $v){
            if($v['pid'] == $pid){
//                dd($html,$level);
                $v['html'] = str_repeat($html, $level);
                $v['level'] = $level;
                $arr[] = $v;
                $arr = array_merge($arr,$this->getHtmlCate($cate,$html,$v['id'],$level+1));
            }
        }

        return $arr;
    }

    /**纯添加sku的属性，属性值关系
     * @param $spu_id int   商品spu_id
     * @param $post   array  提交过来的post数据
     */
    private function add_goods_props($spu_id,$post)
    {
        if(empty($post['specs'])){
            return true;
        }
        $postSkuInfo = isset($post['sku']) ? $post['sku']: [];
        $spu_model = self::find($spu_id);
        $this -> save_sku_info($spu_id,$post['specs'],$postSkuInfo);
        $spu_model -> price = $this->tmp_price;
        $spu_model -> discount_price = $this->tmp_discount_money;
        $spu_model -> stock = $this->tmp_sku_store;
        if(!$spu_model->save()){
            throw new \Exception('商品spu更新失败---'.serialize($spu_model));
        }
    }

    /**纯编辑sku的属性，属性值关系
     * @param $spu_id
     * @param $post
     */
    private function edit_goods_props($spu_id,$post){
        $spu_model = $this -> find($spu_id);
        $postSkuInfo = isset($post['sku']) ? $post['sku']: [];

        if(isset($post['Goods']['price']) || isset($post['Goods']['discount_price']) || isset($post['Goods']['stock'])){
            return true;
        }
        //如果传过来的是未被破坏的table 只需要修改sku的库存 折扣价 和商品编码等属性
        if(isset($post['sku']) && isset($post['sku'][0]['sku_id'])){
            //有属性提交过来
            if(isset($post['specs'])){
                $this -> save_sku_info($spu_id,$post['specs'],$postSkuInfo);
            }
            $spu_model -> price = $this->tmp_price;
            $spu_model -> discount_price = $this->tmp_discount_money;
            $spu_model -> stock = $this->tmp_sku_store;
            if(!$spu_model->save()){
                throw new \Exception('spu表更新失败');
            }
        }else{
            //是已经被破坏的sku_id  需要删除原来的sku_id
            //删除原来的sku_id
            $del_sku_id = isset($post['sku_id'])?$post['sku_id']:[];
            if(!empty($del_sku_id)){
                //将相关的sku_id删除
                Product::query()->whereIn('product_id',$del_sku_id)->update(['disabled'=>'1']);
                sku_props_vals::query()->whereIn('sku_id',$del_sku_id)->update(['disabled'=>'1']);
            }
            //遍历每个sku 添加 sku
            if(!isset($post['specs'])){
                $post['specs'] = [];
            }
            $this->save_sku_info($spu_id,$post['specs'],$postSkuInfo);
            $spu_model -> price = $this->tmp_price;
            $spu_model -> discount_price = $this->tmp_discount_money;
            $spu_model -> stock = $this->tmp_sku_store;

            if(!$spu_model->save()){
                throw new \Exception('商品规格保存失败!');
            }
        }
    }


    /**商品图片的添加或者更新
     * @param $spu_id
     * @param $post
     */
    private function save_goods_iamge($spu_id,$params)
    {
        $post_image_key_arr = empty($params['Image'])?[]:$params['Image']['key'];
        $del_image_id_arr = del_arr(
            array_values($post_image_key_arr),
            array_column(
                GoodsImage::query()
                    ->where('goods_id',$spu_id)
                    ->where('disabled','0')
                    ->get()->toArray()
                ,'goods_image_id')
        );
        if(!empty($del_image_id_arr)){
            GoodsImage::query()->whereIn('id',$del_image_id_arr)->update(['disabled'=>'1','is_default'=>0]);
        }

        $spu_model = $this -> find($spu_id);
        //对商品图片进行编辑或添加操作
        if (isset($params['Image']['url']) && $params['Image']['url']) {
            foreach ($params['Image']['url'] as $image_k => $image_v) {
                //没有加入数据库的图片 则需要插入数据库
                if ($params['Image']['key'][$image_k] == 0) {
                    //插入GoodsImage表
                    $goodsImageModel = GoodsImage::create([
                        'goods_id' => $spu_id,
                        'image' => $image_v,
                    ]);
                    $banner_id = $goodsImageModel -> goods_image_id;
                }else{
                    $banner_id = $params['Image']['key'][$image_k];
                }

                if ($params['Image']['default'][$image_k] == 1) {

                    //将原有的默认图片改为不是默认的
                    $banner_model = GoodsImage::query()->where([['goods_id',$spu_id], ['is_default',1]])->first();
                    if (!empty($banner_model)) {
                        $banner_model->is_default = 0;
                        $banner_model->save();
                    }

                    //将现在的图片改为默认图片
                    $banner_model = GoodsImage::find($banner_id);
                    $banner_model -> is_default = 1;
                    $banner_model -> save();

                    //将默认图片保存进goods表
                    $spu_model -> image = $image_v;
                    $spu_model -> save();
                }
            }
        }else{
            //将该spu的img_url清空
            $spu_model -> image = '';
            $spu_model -> save();
        }
    }

    /**编辑或者修改商品的基本信息(库存，价格，原价，折扣价，商品名) 和商品属性信息
     * @param $spu_id
     * @param $postSpecsArr
     * @param $postSkuInfo
     * @return $this|Model|int 如果是编辑sku信息 则返回影响行数  如果是添加sku则返回sku_model
     * @throws \Exception
     *
     */
    private function save_sku_info($spu_id,$postSpecsArr,$postSkuInfo)
    {
        $res = true;
        if(!$spu_model = $this -> find($spu_id)){
            throw new \Exception('该spu商品不存在');
        }

        foreach($postSpecsArr as $row => $sku){
            if($postSkuInfo[$row]['discount_money']){
                //有一件sku有折扣 就将该spu标记为打折的商品
                $this->tmp_is_discount = 1;
                $this->tmp_discount_money = $postSkuInfo[$row]['discount_money']; //去最后一个折扣价为该spu的折扣价
            }
            if(!$this->tmp_price){
                $this->tmp_price = $postSkuInfo[$row]['price'];
            }
            if($this->tmp_price > $postSkuInfo[$row]['price']){
                //计算出最低价格
                $this->tmp_price = $postSkuInfo[$row]['price'];
            }

            //添加商品的sku
            $sku_data  = [
                'name' => $spu_model->goods_name,
                'title'=> $spu_model->goods_name,
                'bn'   => $postSkuInfo[$row]['bn'],
                'discount_price'=>empty($postSkuInfo[$row]['discount_money'])?0:$postSkuInfo[$row]['discount_money'],
                'goods_id'=>$spu_id,
                'price'=>$postSkuInfo[$row]['price'],
                'stock'=>$postSkuInfo[$row]['store']
            ];
            $this->tmp_sku_store += $postSkuInfo[$row]['store']; //统计库存

            if(isset($postSkuInfo[$row]['sku_id'])){
                $res = Product::query()->where('product_id',$postSkuInfo[$row]['sku_id'])->update($sku_data);
            }else{
                $res = Product::create($sku_data);
            }

            if($res && $res instanceof Product){
                $sku_id = $res -> product_id;
                foreach($sku as $prop_key => $prop_arr){
                    $sku_prop_data = [
                        'sku_id'=>$sku_id,
                        'spu_id'=>$spu_id,
                        'props_id'=>$prop_key,
                        'props_val_id'=>$prop_arr['attr_vid'],
                    ];
                    $db_res = sku_props_vals::create($sku_prop_data);
                    if(!$db_res){
                        throw new \Exception('商品属性表插入失败'.serialize($sku_prop_data));
                    }
                }
            }

            if(!$res){
                throw new \Exception('产品表更新失败');
            }
        }

        return $res;
    }

    /**批量上架或者下架商品
     * @param $spu_id_arr   array   商品id数组
     * @param $marketable   integer 0-下架 1-上架
     * @return int 返回成功的行数
     */
    public function market($spu_id_arr,$marketable)
    {
        return $this -> newQuery() -> whereIn('goods_id',$spu_id_arr) -> update(['marketable'=>$marketable]);
    }

    /**获取商品属性和属性值列表
     * @param $spu_id
     */
    public function api_get_props($spu_id)
    {
        $sku_props_val_list  = DB::table('sku_props_vals as sku')
            ->join('props','sku.props_id','=','props.props_id')
            ->join('props_vals','sku.props_val_id','=','props_vals.props_val_id')
            ->select('sku.sku_id as id','sku.props_id as p_id','sku.props_val_id as v_id','props.name as p_name','props_vals.name as v_name')
            ->where('sku.spu_id','=',$spu_id)
            ->where('sku.disabled','=',0)
            ->where('props.disabled','=',0)
            ->where('props_vals.disabled','=',0)
            ->get()->map(function($value){
                return (array) $value;
            })->toArray();
        $product_arr = [];
        foreach($sku_props_val_list as $sku_props_val){
            if(!isset($product_arr[$sku_props_val['p_id']])){
                $product_arr[$sku_props_val['p_id']]= [
                    'props_id'   => $sku_props_val['p_id'],
                    'props_name' => $sku_props_val['p_name'],
                    'val_list'   => [
                        $sku_props_val['v_id'] =>['val_id' => $sku_props_val['v_id'],'val_name' => $sku_props_val['v_name']],
                    ],
                ];
            }else{
                $product_arr[$sku_props_val['p_id']]['val_list'][$sku_props_val['v_id']] = [
                    'val_id' => $sku_props_val['v_id'],
                    'val_name' => $sku_props_val['v_name']
                ];
            }
        }

        //数组键重排
        $product_arr = array_values($product_arr);
        foreach($product_arr as &$v){
            $v['val_list'] = array_values($v['val_list']);
        }

        return $product_arr;

    }

    /**依据属性和属性值id选出符合的sku信息
     * $props_info_arr = return [
                [
                    "goods_id"  => '1',
                    "props_id"  => '100',
                    "props_val_id" => '100_1',
                ],
                [
                    "goods_id"  => '1',
                    "props_id"  => '400',
                    "props_val_id" => '400_2',
                ]
            ];
     * @param $spu_id
     */
    public function api_get_sku_info($props_info_arr=[])
    {
        if(!is_array($props_info_arr) && is_numeric($props_info_arr)){
            $sku_id_arr =  sku_props_vals::query()
                -> select('sku_id')
                -> distinct()
                -> where('spu_id','=',$props_info_arr)
                -> get()->toArray();
            $sku_id_arr = array_column($sku_id_arr,'sku_id');
        }
        #遍历属性和属性值数组 找出sku_id的交集
        foreach($props_info_arr as $props){
            $sku_list = sku_props_vals::query()
                -> select('sku_id')
                -> distinct()
                -> where('spu_id','=',$props['goods_id'])
                -> where('props_id','=',$props['props_id'])
                -> where('props_val_id','=',$props['props_val_id'])
                -> where('disabled','=',0)
                -> get()->toArray();
            if(!isset($sku_id_arr)){
                $sku_id_arr = array_column($sku_list,'sku_id');
            }else{
                $sku_id_arr = array_intersect($sku_id_arr,array_column($sku_list,'sku_id'));
                if(count($sku_id_arr)==1){
                    break;
                }
            }
        }

        #只有一个命中 则返回该sku的信息
        if(!empty($sku_id_arr) && count($sku_id_arr) == 1){
            $sku = $this -> get_multiple_sku($sku_id_arr);
        }

        #有多个sku_id命中 则返回价格区间和总共的仓库数量
        if(!empty($sku_id_arr) && count($sku_id_arr) > 1 ){
            $sku = $this -> get_multiple_sku($sku_id_arr);
        }

        #没有命中则返回所有sku价格区间和库存总量
        if(empty($sku_id_arr)){
            $sku_list = sku_props_vals::query()
                -> select('sku_id')
                -> distinct()
                -> where('spu_id','=',$props['goods_id'])
                -> where('disabled','=',0)
                -> get()->toArray();
            $sku_id_arr = array_column($sku_list,'sku_id');
            $sku = $this -> get_multiple_sku($sku_id_arr);
        }

        return $sku;
    }

    /**获取商品详情信息
     * @param $spu_id  int 商品的spu_id
     * @return array   商品详情信息
     */
    public function api_get_goods_detail($spu_id)
    {
        $spu_info = self::query()
            -> select('goods_name','price','discount_price','sales_num','stock','ship_address','detail_content')
            -> where('goods_id','=',$spu_id)
            -> where('disabled','=',0)
            -> first();
//        dd($spu_info->toArray());
        if(empty($spu_info)){
            $spu_info = [];
        }else{
            $spu_info -> toArray();
        }

        //获取商品轮播图
        $spu_info['banner'] = GoodsImage::api_get_goods_banner($spu_id);

        //用户评论数量标志
        $spu_info['comment_num'] = Comment::query()->where('goods_id','=',$spu_id)->count();

        //获取商品的价格区间
//        $skus_info = $this -> api_get_sku_info($spu_id);

        $spu_info['is_discount'] = empty($spu_info['discount_price']) ? 0 : 1;
        return $spu_info;
    }

    /**$sku_id_arr中的sku_id的数量必须大于1
     * 根据sku_id数组返回多个sku的信息
     */
    private function get_multiple_sku($sku_id_arr)
    {
        $sku_arr = Product::query()
            -> select('product_id AS sku_id','name','title','price','discount_price','stock','goods_id')
            -> whereIn('product_id',$sku_id_arr)->get()->toArray();
        $sku = [
            'goods_id' => $sku_arr[0]['goods_id'],
            'sku_id'=> count($sku_id_arr) ==1?array_values($sku_id_arr)[0]:'',
            'name'  => $sku_arr[0]['name'],
            'title' => $sku_arr[0]['title'],
            'min_price' => $sku_arr[0]['price'],
            'max_price' => $sku_arr[0]['price'],
            'min_discount_price' => $sku_arr[0]['discount_price'],
            'max_discount_price' => $sku_arr[0]['discount_price'],
            'stock' => 0,
        ];
        foreach($sku_arr as $sku_one){
//            $sku['sku_id'][] = $sku_one['sku_id'];
            //库存累加
            $sku['stock']+=$sku_one['stock'];

            #计算最小和最大的价格
            $sku['min_price'] = $sku_one['price'] <  $sku['min_price'] ?$sku_one['price']:$sku['min_price'];
            $sku['max_price'] = $sku_one['discount_price'] >  $sku['max_price'] ?$sku_one['discount_price']:$sku['max_price'];

            #计算最小和最大的打折价格
            $sku['min_discount_price'] = $sku_one['discount_price'] <  $sku['min_discount_price'] ?$sku_one['discount_price']:$sku['min_discount_price'];
            $sku['max_discount_price'] = $sku_one['discount_price'] >  $sku['max_discount_price'] ?$sku_one['discount_price']:$sku['max_discount_price'];

            #计算是否其中一个sku打折
            if(!$sku['is_discount']){
                $sku['is_discount'] = ($sku_one['discount_price'] == '0.00' || empty($sku_one['discount_price'])) ? 0 : 1;
            }
        }

        #确保价格区间出现在有价格差的时候
        if($sku['min_price'] != $sku['max_price']){
            $sku['price'] = $sku['min_price'].'-'.$sku['max_price'];
        }else{
            $sku['price'] = $sku['min_price'];
        }

        #确保价格区间出现在有价格差的时候
        if($sku['min_discount_price'] != $sku['max_discount_price']){
            $sku['discount_price'] = $sku['min_discount_price'].'-'.$sku['max_discount_price'];
        }else{
            $sku['discount_price'] = $sku['min_discount_price'];
        }

//        unset($sku['min_price'],$sku['max_price'],$sku['min_discount_price'],$sku['max_discount_price']);
        return $sku;
    }




}
